package tool

import cats.data.Validated
import implicits.Implicits._
import org.apache.commons.lang3.StringUtils

/**
 * Created by Administrator on 2019/12/20
 */
class FileValidTool(lines: List[List[String]]) {

  val headers = lines.head
  val hasHeaders = List("Age", "BMI", "FBG", "GGT", "HDLch", "TBil", "ALB", "SampleID", "PLT", "AST")
  val fileInfo="文件"

  def validHeadersRepeat = {
    val repeatHeaders = headers.diff(headers.distinct)
    val valid = repeatHeaders.isEmpty
    Validated.cond(valid, true, s"文件表头 ${repeatHeaders.head} 重复!")
  }

  def validHeadersHas = {
    val valid = StringUtils.isBlank(lines.head.mkString("\t"))
    Validated.cond(!valid, true, s"首行数据（表头）缺失!")
  }

  def validHeadersExist = {
    val noExistHeaders = hasHeaders.diff(headers)
    val valid = noExistHeaders.isEmpty
    Validated.cond(valid, true, s"文件表头 ${noExistHeaders.head} 不存在!")
  }

  def validAgeColumn = {
    val header = "Age"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 100 || column.toDouble < 18
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为18-100之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validBmiColumn = {
    val header = "BMI"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 500 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-500之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validFbgColumn = {
    val header = "FBG"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 100 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-100之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validGgtColumn = {
    val header = "GGT"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 2000 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-2000之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validHdLchColumn = {
    val header = "HDLch"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 100 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-100之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validTbilColumn = {
    val header = "TBil"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 500 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-500之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validAlbColumn = {
    val header = "ALB"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 1000 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-1000之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validPltColumn = {
    val header = "PLT"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 1000 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-1000之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }

  def validAstColumn = {
    val header = "AST"
    val totalColumns = lines.selectOneColumn(header)
    val op = totalColumns.filter { column =>
      !column.isDouble || column.toDouble > 1000 || column.toDouble < 0
    }.headOption
    val inValid = op.isEmpty
    val inMessage = if (!inValid) {
      val value = op.get
      val j = headers.indexOf(header)
      val i = totalColumns.lastIndexOf(value)
      s"${fileInfo}第${i + 2}行第${j + 1}列必须为0-1000之间的实数!"
    } else ""
    Validated.cond(inValid, true, inMessage)
  }


  def validDoubleColumn = {
    val doubleColumns = List("Age", "BMI", "FBG", "GGT", "HDLch", "TBil", "ALB", "PLT", "AST")
    val info = doubleColumns.map { header =>
      val totalColumns = lines.selectOneColumn(header)
      val op = totalColumns.filter { column =>
        !column.isDouble
      }.headOption
      val inValid = op.isEmpty
      val inMessage = if (!inValid) {
        val value = op.get
        val j = headers.indexOf(header)
        val i = totalColumns.lastIndexOf(value)
        s"文件第${i + 2}行第${j + 1}列必须为实数!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2)
    Validated.cond(valid, true, messages.head)
  }

  def validColumnNum = {
    val info = lines.drop(1).zipWithIndex.map { case (tmpColumns, i) =>
      val columns = tmpColumns
      val inValid = columns.size <= headers.size
      val inMessage = if (!inValid) {
        s"文件第${i + 2}行列数不正确,存在多余列!"
      } else ""
      (inValid, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2)
    Validated.cond(valid, true, messages.head)
  }

  def validNonEmpty = {
    val info = lines.drop(1).zipWithIndex.map { case (columns, i) =>
      val lineMap = headers.zip(columns).toMap
      val op = lineMap.filter{case(header,value)=>
        hasHeaders.contains(header)
      }.values.toList.filter { column =>
        StringUtils.isEmpty(column)
      }.headOption
      val inMessage = if (op.nonEmpty) {
        val j = columns.indexOf(op.get)
        s"文件第${i + 2}行第${j + 1}列为空!"
      } else ""
      (op.isEmpty, inMessage)
    }
    val valid = info.forall(_._1)
    val messages = info.map(_._2)
    Validated.cond(valid, true, messages.head)
  }

}

object FileValidTool {

  def valid(lines: List[List[String]]) = {
    val fileValidTool = new FileValidTool(lines)
    import fileValidTool._
    validHeadersHas.andThen { b =>
      validHeadersRepeat
    }.andThen { b =>
      validHeadersExist
    }.andThen { b =>
      validColumnNum
    }.andThen { b =>
      validNonEmpty
    }.andThen { b =>
      validDoubleColumn
    }.andThen{b=>
      validAgeColumn
    }.andThen{b=>
      validBmiColumn
    }.andThen{b=>
      validGgtColumn
    }.andThen{b=>
      validHdLchColumn
    }.andThen{b=>
      validAlbColumn
    }.andThen{b=>
      validPltColumn
    }

  }

}
